﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using CanvasControl.Behaviors;
using GraphDrawing.Graph.Behaviors;
using GraphDrawing.Interface;
using GraphDrawing.Model;
using GraphDrawing.Resources;

namespace GraphDrawing.View
{
    public partial class Form1 : Form, IView
    {
        readonly Presenter presenter;
        readonly Dictionary<string, Panel> toolboxControls = new Dictionary<string, Panel>();

        public Form1(Presenter presenter)
        {
            this.presenter = presenter;
            InitializeComponent();
        }

        public void Initialize(MyModel model)
        {
            canvasView1.Controller.AddBehavior(new BackgroundDrawingBehavior(5, 256)
            {
                Background = {Color = Color.White, Border = {Color = Color.Red}},
                Grid = {Color = Color.LightGray, DashStyle = DashStyle.Dash}
            });
            canvasView1.Controller.AddBehavior(new GraphVisualizationBehavior(model.ZOrderModel, model.ViewContainer)
            {
                SelectionBoxAppearance = { Color = Color.FromArgb(128, Color.Orange), Border = { Color = Color.DarkOrange } },
                SelectedConnection = { Width = 3 }
            });
            canvasView1.Controller.AddBehavior(new DebugBehavior(Keys.D, true));
            foreach (var tool in model.ToolboxItems)
                RegisterToolboxItem(tool);
        }

        public void UpdateView()
        {
            canvasView1.UpdateView();
        }

        void OnToolboxItemMouseDown(object sender, EventArgs e)
        {
            var button = (Control)sender;
            var id = (string) button.Tag;
            presenter.DragSourceController.RequestBeginDrag(id);
        }

        public void BeginDrag(object id, DragDropEffects effect)
        {
            var obj = toolboxControls[(string) id];
            obj.BackColor = Color.Azure;
            obj.DoDragDrop(id, effect);
        }

        public void EndDrag(object id)
        {
            var obj = toolboxControls[(string)id];
            obj.BackColor = SystemColors.Control;
        }

        void OnToolboxItemDragLeave(object sender, EventArgs e)
        {
            presenter.DragSourceController.OnLeave();
        }

        void OnToolboxItemQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            var leftButtonPressed = MouseButtons.HasFlag(MouseButtons.Left);
            e.Action = presenter.DragSourceController.CheckDraggingState(e.EscapePressed, leftButtonPressed);
        }

        void RegisterToolboxItem(ToolboxItem item)
        {
            var pane = new Panel();
            pane.Text = item.DisplayName;
            pane.Width = 52;
            pane.Height = 52;
            if (!string.IsNullOrWhiteSpace(item.ImageKey))
                pane.BackgroundImage = ResourceFactory.GetImage(item.ImageKey);
            var gap = (flowLayoutPanel1.ClientSize.Width - pane.Width)/2;
            pane.Margin = new Padding(gap, pane.Margin.Top, pane.Margin.Right, pane.Margin.Bottom);
            pane.Tag = item.Id;
            pane.AllowDrop = true;
            pane.MouseDown += OnToolboxItemMouseDown;
            pane.DragLeave += OnToolboxItemDragLeave;
            pane.QueryContinueDrag += OnToolboxItemQueryContinueDrag;
            pane.DragOver += OnToolboxItemDragOver;
            flowLayoutPanel1.Controls.Add(pane);
            toolboxControls.Add(item.Id, pane);
        }

        void OnToolboxItemDragOver(object sender, DragEventArgs e)
        {
            Debug.WriteLine("Source.DragOver");
        }

        void CanvasDragEnter(object sender, DragEventArgs e)
        {
            e.Effect = presenter.DropTargetController.CheckCanAcceptDrop(e.Data, e.AllowedEffect) ? DragDropEffects.Copy : DragDropEffects.None;
        }

        void CanvasDragOver(object sender, DragEventArgs e)
        {
            presenter.DropTargetController.OnProcessDragging(e.Data, ScreenToCanvasCoordinates(e.X, e.Y));
        }

        void CanvasDragLeave(object sender, EventArgs e)
        {
            presenter.DropTargetController.OnLeave();
        }

        void CanvasDragDrop(object sender, DragEventArgs e)
        {
            presenter.DropTargetController.CompleteDrop(e.Data, ScreenToCanvasCoordinates(e.X, e.Y));
        }

        Point ScreenToCanvasCoordinates(int x, int y)
        {
            var point = canvasView1.PointToClient(new Point(x, y));
            return canvasView1.Controller.Model.ViewPort.ClientToGlobal(point);
        }
    }
}
